package com.suxii.handler;

import com.google.gson.Gson;
import com.suxii.pojo.*;
import com.suxii.service.UserService;
import io.netty.channel.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

@Slf4j
@ChannelHandler.Sharable
@Component("STATE_HANDLER")
public class StateHandler extends SimpleChannelInboundHandler<Msg> {


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("{} 错误信息:{}",ctx.channel(), cause.getMessage());
        if (ctx.channel().isActive()) {
            StateHandler.noActive(ctx);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //if (ctx.channel().isActive()) {
            log.info("客户端连接断开离线,{}", ctx.channel());
            StateHandler.noActive(ctx);
        //}
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    public static void noActive(ChannelHandlerContext ctx) {
        Integer uid;
        if ((uid = ChannelsHandler.uidlMap.get(ctx.channel())) != null) {
            ChannelsHandler.removeChannel(uid);
        }
        ctx.channel().close();
        log.info("channelGroup:{}", ChannelsHandler.channelGroup.size());
        log.info("channelMap:{}", ChannelsHandler.channelMap.size());
        log.info("uidlMap:{}", ChannelsHandler.uidlMap.size());
    }


    @Autowired
    private UserService userService;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Msg msg) throws Exception {
        if (msg.getType() == Msg.CHAT_MSG) {

            // 判断当前channel是否登录
            // channel为空则绑定
            if (ChannelsHandler.uidlMap.get(ctx.channel()) == null) {
                int uid = msg.getUid();
                // 用户登录绑定
                isExist(uid,ctx);
                /*
                登录成功之后加载消息缓存
                加载新朋友缓存
                移除该用户不在线的缓存
                 */

                //消息缓存
                redisMessage(ctx,uid);

                //新朋友缓存
                friendCache(ctx,uid);

                //移除用户不在线
                isUserCache(uid);
            }else {
                log.info("{}", msg);
                ctx.fireChannelRead(msg);
            }
        }
        // 添加朋友
        else if (msg.getType()==Msg.FRIEND_MSG){
            FriendMsg friendMsg= (FriendMsg) msg;
            friendHandler(friendMsg,ctx);
        }
    }

    // 用户登录
    private void isExist(int uid,ChannelHandlerContext ctx){
        // 通过uid查询数据库用户是否存在
        Long cuu = userService.lambdaQuery()
                .select(ChatUser::getUid)
                .eq(ChatUser::getUid, uid)
                .count();
        if (cuu>0){// uid存在绑定channel，不存在则移除当前channel
            ChannelsHandler.removeChannel(uid);// 先移除再绑定
            ChannelsHandler.bindChannel(uid, ctx.channel());
            log.info("{}:已连接",ctx.channel());
        }else {
            noActive(ctx);
        }
    }

    // 新朋友申请缓存
    private void friendHandler(FriendMsg msg,ChannelHandlerContext ctx){
        int aimUid = msg.getUuid();
        // 通过uid获取目标channel
        Channel aimCh = ChannelsHandler.channelMap.get(aimUid);
        // 过滤匹配目标产channel
        Stream<Channel> stream = ChannelsHandler.channelGroup.stream().filter(o -> o.equals(aimCh));
        if (stream.findAny().isPresent()) { // 判断流中是不是当前目标  Present -》 目前
            ChannelsHandler.channelGroup.stream().filter(o -> o.equals(aimCh)).forEach(p -> p.writeAndFlush(msg));
        }else {
            // 流中不存在则发送缓存
            SetOperations friendList = redisTemplate.opsForSet();
            friendList.add("friend_"+msg.getUuid(),String.valueOf(msg.getUid()));
        }
    }

    private void friendCache(ChannelHandlerContext ctx,int uid){
        // 取出List集合全部数据
        SetOperations friendList = redisTemplate.opsForSet();
        Set<String> uuid = friendList.members("friend_"+uid);
        if (uuid.size()>0) {
            // 发送缓存消息
            uuid.forEach(u -> ctx.channel().writeAndFlush(new FriendMsg(Integer.parseInt(u), uid)));
            // 删除缓存
            friendList.pop("friend_"+uid);
        }

    }

    @Autowired
    private RedisTemplate redisTemplate;


    private void redisMessage(ChannelHandlerContext ctx, int uid) {
        // 以自己的uid作为key，hset 目标uid，消息内容
        HashOperations msgRedis = redisTemplate.opsForHash();
        msgRedis.keys(String.valueOf(uid)).forEach(aimUid -> {
            String context = (String)msgRedis.get(String.valueOf(uid), aimUid);
            new Gson().fromJson(context, List.class).forEach((message)->{
                ctx.channel().writeAndFlush(new ChatMsg("",Integer.parseInt((String) aimUid),(String) message,uid));
            });
            log.info("{} 发消息:{}",aimUid,context);
            //删除缓存
            msgRedis.delete(String.valueOf(uid),aimUid);
            ChannelsHandler.messageCache.remove(uid);
            log.info("{}",ChannelsHandler.messageCache.size());
        });
    }

    private void isUserCache(int uid){
        // 用户上线就删除不在线的消息缓存
        if (ChannelsHandler.noConnectUserCache.get(uid)!=null) {
            ChannelsHandler.noConnectUserCache.remove(uid);
        }
    }
}
